import actors.{Exit, Actor}
import java.util.Date
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.io.FileWriter

object Const{
    val LOG_FILE_PREFIX = "_actor_"
    val LOG_FILE_SUFFIX = "_log"
    def getTime(): String = {
        return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
    }
    object Test
}

// Program name (main function), running time, actor being logged
class ActorLog (programName: String, actorStartingTime: String, actor: Actor) {
    val logFileName = programName + "_" + actorStartingTime + Const.LOG_FILE_PREFIX +
      actor.toString + Const.LOG_FILE_SUFFIX

    val logFile = new FileWriter(logFileName)
    val actorRef = actor
    logFile.write("Log file for actor " + actor.toString + "\n")

    var numOfMsgIn = 0.toLong
    var numOfMsgOut = 0.toLong

    def msg_in(msg: Any, senderName: String) {
        numOfMsgIn += 1
        /*
        logFile.write("[" + Const.getTime() + "]"  + "[Msg_in]" + "[" + numOfMsgIn + "]" +
        senderName + " -> " +  this.actorRef.toString + " : " + msg.toString)
        */
        logFile.write("[" + Const.getTime() + "]"  + "[Msg_in]" + "[" + numOfMsgIn + "]" +
          "[" +  msg.toString + "]")
        logFile.write("\n")
        logFile.flush()
        //println("[Msg_in] " + senderName + " -> " +  this.actorRef.toString + " : " + msg.toString)
    }
    def msg_out(msg: Any, receiverName: String) {
        numOfMsgOut += 1
        /*
        logFile.write("[" + Const.getTime() + "]"  + "[Msg_out]" + "[" + numOfMsgOut + "]" +
          this.actorRef.toString + " -> " + receiverName + " : " + msg.toString)
        */
        logFile.write("[" + Const.getTime() + "]"  + "[Msg_out]" + "[" + numOfMsgOut + "]" +
          "[" + receiverName + "]" + "[" + msg.toString + "]")
        logFile.write("\n")
        logFile.flush()
    }
    /*
    def msg_in(simpleMsg: String){
        logFile.write("[Msg_in] " + actorRef.toString)
        logFile.write("\n")
        logFile.flush()
    }
    def msg_out(simpleMsg: String){
        logFile.write("[Msg_out] " + actorRef.toString)
        logFile.write("\n")
        logFile.flush()
    }
    */
    def flush(){
        logFile.flush()
    }
}


abstract class LoggedActor (programName: String) extends Actor{

    val log = new ActorLog(programName, Const.getTime(), this)

    /*
    override def !(msg: Any) {
        log.msg_out(this.toString)
    } */

    /*
    override def react(handler: PartialFunction[Msg, Unit]): Nothing = {
        synchronized { drainSendBuffer(mailbox) }
        searchMailbox(mailbox, handler, false)
        throw Actor.suspendException
    }
    */

    // represent ! function
    def ->(receiver: Actor, msg: Any){
        log.msg_out(msg, receiver.toString)
        receiver ! msg
    }

    // represent !! function
    def --> (receiver: Actor, msg: Any): Future[Any] = {
        log.msg_out(msg, receiver.toString)
        return receiver !! msg
    }

    // represent !?(msg) function
    def ==>(receiver: Actor, msg: Any): Any = {
        log.msg_out(msg, receiver.toString)
        return receiver !? msg
    }

    // represent !?(msec,msg) function
    def ==>(receiver: Actor, msec: Long, msg: Any): Option[Any] = {
        log.msg_out(msg, receiver.toString)
        return receiver !? (msec, msg)
    }

    // represent react function
    def LReact(handler: PartialFunction[Any, Unit]): Nothing = {
        react {
            /*
            case Exit =>
                log.flush()
            */
            case x =>
                log.msg_in(x.toString, sender.toString)
                handler(x)
        }
    }
}

